package com.franklin.java.action.sql.run.ui;

import com.franklin.java.action.sql.run.MybatisSql;
import com.franklin.java.action.sql.run.MybatisParam;
import com.franklin.java.api.ui.jpanel.AbstractComponent;
import com.franklin.java.api.ui.jpanel.button.MyButton;
import com.franklin.java.service.database.DataSourceServiceSupport;
import com.franklin.java.service.database.MyJdbcConsole;
import com.franklin.java.utils.DocumentUtils;
import com.franklin.java.utils.EditorUtils;
import com.franklin.java.utils.SwingUtils;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ui.FormBuilder;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 执行SQL表单
 * @author Franklin
 * @since 2021/9/22 12:15
 */
public class RunSqlForm extends AbstractComponent {
    private JPanel mainPanel;
    private JPanel sqlPanel;
    private MyButton executeSqlMyButton;
    private MyButton cancelMyButton;
    private JPanel paramPanel;
    private JSplitPane jSplitPane;
    private MyButton chooseDSExecuteButton;

    private Editor editor;

    private Map<String,JComponent> elExpressionComponentMap = new LinkedHashMap<>();

    private PsiElement sqlActionElement;
    private Project project;
    private MybatisSql<?> mybatisSql;

    public RunSqlForm(PsiElement sqlActionElement) {
        this.sqlActionElement = sqlActionElement;
        this.project = sqlActionElement.getProject();
        //先保存Document
        PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(this.project);
        Document document = psiDocumentManager.getDocument(sqlActionElement.getContainingFile());
        DocumentUtils.writeSync(this.project,() -> psiDocumentManager.commitDocument(document));

        this.mybatisSql = MybatisSql.getSql(sqlActionElement);

        init();
    }

    @Override
    public JPanel getMainPanel() {
        return mainPanel;
    }

    public MyButton getCancelMyButton() {
        return cancelMyButton;
    }

    /**
     * 初始化<br>
     * @author Franklin
     * @since 2021/9/22 12:24
     * @param :
     * @return void
     */
    private void init() {
        initSplitPane();
        initParamPanel();
        initSqlPanel();
        initExecuteSqlButton();
        initChooseDSExecuteButton();
    }

    /**
     * 选择数据源执行<br>
     * @author Franklin
     * @since 2021/9/24 10:06
     * @param :
     * @return void
     */
    private void initChooseDSExecuteButton() {
        this.chooseDSExecuteButton.addActionListener(e -> {
            String sql = this.editor.getDocument().getText();
            MyJdbcConsole jdbcConsole = DataSourceServiceSupport.getInstance().getJdbcConsole(project, sql);
            JBPopup datasourceChoosingPopup = jdbcConsole.getDatasourceChoosingPopup();
            datasourceChoosingPopup.showCenteredInCurrentWindow(project);
//            this.cancelMyButton.doClick();
        });
    }

    /**
     * 初始化SQL运行按钮<br>
     * @author Franklin
     * @since 2021/9/23 14:55
     * @param :
     * @return void
     */
    private void initExecuteSqlButton() {
        this.executeSqlMyButton.addActionListener(e -> {
            String sql = this.editor.getDocument().getText();
            MyJdbcConsole jdbcConsole = DataSourceServiceSupport.getInstance().getJdbcConsole(project, sql);
            if (!jdbcConsole.executeQuery()) {
                JBPopup datasourceChoosingPopup = jdbcConsole.getDatasourceChoosingPopup();
                datasourceChoosingPopup.showInCenterOf(this.mainPanel);
            }
            this.cancelMyButton.doClick();
        });
    }

    /**
     * 初始化分割线<br>
     * @author Franklin
     * @since 2021/9/23 14:12
     * @param :
     * @return void
     */
    private void initSplitPane() {
        jSplitPane.setDividerLocation(500);
    }

    /**
     * 初始化参数面板<br>
     * @author Franklin
     * @since 2021/9/23 14:16
     * @param :
     * @return void
     */
    private void initParamPanel() {
        List<MybatisParam> paramList = mybatisSql.getParamList();
        ActionListener actionListener = e -> refreshSql();
        int size = paramList.size();
        this.paramPanel.setLayout(SwingUtils.createLayoutManager(size,1));
        Dimension dimension = new Dimension(500, 600);
        this.paramPanel.setPreferredSize(dimension);
        this.paramPanel.setMinimumSize(dimension);
        Dimension childSize = new Dimension(500, -1);
        for (int i = 0; i < size; i++) {
            MybatisParam mybatisParam = paramList.get(i);
            JComponent component = null;
            if (mybatisParam.isTest()) {
                JBCheckBox jbCheckBox = new JBCheckBox(String.format("[%s] == true", mybatisParam.getElExpression()));
                jbCheckBox.addActionListener(actionListener);
                component = jbCheckBox;
                this.addCell(paramPanel, jbCheckBox, i, 0, childSize);
            } else {
                JBTextField textField = new JBTextField();
                if (mybatisParam.isString()) {
                    textField.setText("''");
                }
                textField.addActionListener(actionListener);
                textField.addKeyListener(new KeyListener() {
                    @Override
                    public void keyTyped(KeyEvent e) {

                    }

                    @Override
                    public void keyPressed(KeyEvent e) {

                    }

                    @Override
                    public void keyReleased(KeyEvent e) {
                        refreshSql();
                    }
                });
                JPanel panel = FormBuilder.createFormBuilder()
                    .addLabeledComponent(mybatisParam.getElExpression(), textField)
                    .getPanel();
                component = textField;
                this.addCell(paramPanel, panel,  i, 0, childSize);
            }
            this.elExpressionComponentMap.put(mybatisParam.getElExpression(), component);
        }
    }

    /**
     * 初始化SQL面板<br>
     * @author Franklin
     * @since 2021/9/23 14:16
     * @param :
     * @return void
     */
    private void initSqlPanel() {
        EditorFactory editorFactory = EditorFactory.getInstance();
        Document document = editorFactory.createDocument("");
        this.editor = editorFactory.createEditor(document);
        EditorUtils.initEditor(this.editor);

        this.sqlPanel.removeAll();
        this.sqlPanel.setLayout(SwingUtils.createLayoutManager(1, 1));
        JComponent editorComponent = this.editor.getComponent();

        refreshSql();

        this.addCell(this.sqlPanel,editorComponent,0,0,new Dimension(500,600));
    }

    private void refreshSql(){
        String sql = mybatisSql.resolveSqlFromForm(this.elExpressionComponentMap);
        this.refreshSqlPanel(this.editor,sql);
    }

    private void refreshSqlPanel(Editor editor,CharSequence content){
        ((EditorImpl) editor).setViewer(false);
        Project project = sqlActionElement.getProject();
        DocumentUtils.writeSync(project, () -> editor.getDocument().setText(content));
        ((EditorEx) editor)
            .setHighlighter(EditorHighlighterFactory.getInstance()
                .createEditorHighlighter(project, mybatisSql.getMapperMethodName() + ".sql")
            );
    }
}
